home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Over 1,000 Windows 95 Programs
/
Over 1000 Windows 95 Programs (Microforum) (Disc 1).iso
/
1258
/
samples
/
stocktic.jav
< prev
next >
Wrap
Text File
|
1996-05-05
|
14KB
|
533 lines
/*
* @(#)StockTicker.java 1.10 95/10/13 Jim Graham
*
* Copyright (c) 1994-1995 Sun Microsystems, Inc. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
* without fee is hereby granted.
* Please refer to the file http://java.sun.com/copy_trademarks.html
* for further important copyright and trademark information and to
* http://java.sun.com/licensing.html for further important licensing
* information for the Java (tm) Technology.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*
* THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
* CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
* PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
* NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
* SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
* SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
* PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). SUN
* SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
* HIGH RISK ACTIVITIES.
*/
import java.applet.Applet;
import java.util.Vector;
import java.util.StringTokenizer;
import java.util.Hashtable;
import java.awt.Graphics;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Color;
/**
* A simple class to read a stock quote data stream and display the most
* recent quotes in a streaming stock ticker.
*
* @author Jim Graham
* @version 1.10, 10/13/95
*/
public
class StockTicker extends Applet implements StockWatcher {
Vector Symbols;
int numSymbols;
int delay = 10;
int fetchdelay = 60;
int deltat = 50;
int scrolldelta;
int scrollPos;
boolean fudge = false;
QuoteQueue qq = new QuoteQueue();
float quote[];
float prevquote[];
boolean feedError[];
boolean quoteChange[];
boolean quoteKnown[];
boolean prevKnown[];
TickerPaintDaemon daemon;
StockStreamParser ssp;
Font symbolFont;
Font fractFont;
Font quoteFont;
FontMetrics symbolFM;
FontMetrics fractFM;
FontMetrics quoteFM;
Color errorColor;
Color freshColor;
Color staleColor;
Color bgColor;
private static Hashtable colorCache = new Hashtable();
static {
colorCache.put("red", Color.red);
colorCache.put("green", Color.green);
colorCache.put("blue", Color.blue);
colorCache.put("cyan", Color.cyan);
colorCache.put("magenta", Color.magenta);
colorCache.put("yellow", Color.yellow);
colorCache.put("orange", Color.orange);
colorCache.put("pink", Color.pink);
colorCache.put("white", Color.white);
colorCache.put("lightgray", Color.lightGray);
colorCache.put("gray", Color.gray);
colorCache.put("darkgray", Color.darkGray);
colorCache.put("black", Color.black);
}
/**
* Initialize the Applet. Get values from attributes.
* @see browser.Applet
*/
public void init() {
String s;
symbolFont = new Font("Helvetica", Font.BOLD, 18);
symbolFM = getFontMetrics(symbolFont);
quoteFont = new Font("Helvetica", Font.PLAIN, 16);
quoteFM = getFontMetrics(quoteFont);
fractFont = new Font("Helvetica", Font.PLAIN, 12);
fractFM = getFontMetrics(fractFont);
s = getParameter("stocks");
if (s == null)
s = "SUNW|HWP|SGI|MSFT|INTC|IBM|DEC|CY|ADBE|AAPL|SPX|ZRA";
Symbols = new Vector(10);
StringTokenizer st = new StringTokenizer(s, "|");
scrolldelta = 0;
while (st.hasMoreTokens()) {
String stockname = st.nextToken();
Symbols.addElement(stockname);
scrolldelta += symbolFM.stringWidth(stockname)
+ quoteFM.stringWidth("99+")
+ fractFM.stringWidth("3/4 1/2")
+ QuoteSnapshot.margin;
}
numSymbols = Symbols.size();
quote = new float[numSymbols];
prevquote = new float[numSymbols];
feedError = new boolean[numSymbols];
quoteChange = new boolean[numSymbols];
quoteKnown = new boolean[numSymbols];
prevKnown = new boolean[numSymbols];
s = getParameter("fudge");
if (s != null) fudge = s.equals("true");
s = getParameter("delay");
if (s != null) fetchdelay = Integer.parseInt(s);
s = getParameter("scrollt");
if (s != null)
delay = Integer.parseInt(s);
else
delay = numSymbols;
s = getParameter("deltat");
if (s != null) deltat = Integer.parseInt(s);
errorColor = getColorAttribute("errorfg", Color.yellow);
freshColor = getColorAttribute("freshfg", Color.green);
staleColor = getColorAttribute("stalefg", Color.white);
bgColor = getColorAttribute("bgcolor", Color.darkGray);
scrolldelta = scrolldelta * deltat / (delay * 1000);
scrollPos = size().width;
}
private Color getColorAttribute(String name, Color defcolor) {
String s = getParameter(name);
if (s == null)
return defcolor;
s = s.toLowerCase();
defcolor = (Color) colorCache.get(s);
if (defcolor != null)
return defcolor;
int colorval = java.lang.Integer.parseInt(s, 16);
int r = (colorval >> 16) & 0xff;
int g = (colorval >> 8) & 0xff;
int b = colorval & 0xff;
defcolor = new Color(r, g, b);
colorCache.put(s, defcolor);
return defcolor;
}
/**
* Run the quote data fetcher.
* @see java.lang.Thread
*/
public synchronized void startSSP() {
ssp = new StockStreamParser(this, getDocumentBase(),
fudge, fetchdelay, 0);
String stocks[] = new String[numSymbols];
Symbols.copyInto(stocks);
ssp.setStock(stocks);
ssp.start();
}
public synchronized void feedEOF(StockStreamParser ssp) {
if (this.ssp == ssp) {
this.ssp = null;
}
}
int findSymbol(String symbol) {
int index = Symbols.indexOf(symbol);
if (index < 0) {
System.out.println("Unrequested quote received for " + symbol);
}
return index;
}
public void newHigh(String symbol, double value) {
}
public void newLow(String symbol, double value) {
}
public void newClose(String symbol, double value) {
int index = findSymbol(symbol);
if (index >= 0) {
prevquote[index] = (float) value;
prevKnown[index] = true;
}
}
public void newQuote(String symbol, double value) {
int index = findSymbol(symbol);
if (index >= 0) {
if (quote[index] != (float) value) {
quote[index] = (float) value;
quoteChange[index] = true;
}
quoteKnown[index] = true;
}
}
public void newQuote(String symbol, double value, int time) {
System.out.println("Ticker ignoring history of " + value
+ "@" + time +" for " + symbol);
}
public void setFeedError(String symbol, boolean error) {
int index = findSymbol(symbol);
if (index >= 0) {
feedError[index] = error;
if (error && !prevKnown[index]) {
prevquote[index] = quote[index];
}
}
}
public void flushQuotes() {
}
int nextQuote = 0;
public void scroll() {
if (qq.getHead() == null) {
scrollPos = size().width;
} else {
scrollPos -= scrolldelta;
}
repaint();
}
private int lastScrollPos;
/**
* Update the current frame.
*/
public synchronized void update(Graphics g, int startpos) {
int pos = scrollPos;
QuoteSnapshot qs = qq.getHead();
int fallen = 0;
while (qs != null) {
if (pos + qs.width > startpos) {
pos = qs.paint(g, pos);
} else {
pos += qs.width;
}
if (pos <= 0) {
scrollPos = pos;
fallen++;
}
qs = qs.next;
}
while (fallen-- > 0) {
qq.dequeue();
}
int numskipped = 0;
while (pos <= size().width) {
Color color;
if (!feedError[nextQuote]
&& (!quoteKnown[nextQuote] || !prevKnown[nextQuote]))
{
if (++nextQuote == numSymbols) {
nextQuote = 0;
}
if (++numskipped == numSymbols) {
break;
}
continue;
}
numskipped = 0;
if (feedError[nextQuote]) {
color = errorColor;
} else {
if (quoteChange[nextQuote]) {
color = freshColor;
quoteChange[nextQuote] = false;
} else {
color = staleColor;
}
}
qs = qq.enqueue(this,
(String) Symbols.elementAt(nextQuote),
quote[nextQuote],
prevquote[nextQuote],
color);
if (++nextQuote == numSymbols) {
nextQuote = 0;
}
pos = qs.paint(g, pos);
}
lastScrollPos = scrollPos;
}
/**
* Update the current frame.
*/
public synchronized void update(Graphics g) {
int width = size().width;
int height = size().height;
if (qq.getHead() == null) {
scrollPos = width;
paint(g);
} else {
int delta = lastScrollPos - scrollPos;
g.copyArea(delta, 0, width - delta, height, -delta, 0);
g.clipRect(width - delta, 0, delta, height);
update(g, width - delta);
}
}
/**
* Update the current frame.
*/
public synchronized void paint(Graphics g) {
g.setColor(bgColor);
g.fillRect(0, 0, size().width, size().height);
update(g, 0);
}
/**
* Start the applet by forking an animation thread.
*/
public synchronized void start() {
if (ssp == null) {
startSSP();
}
if (daemon == null) {
daemon = new TickerPaintDaemon(this);
daemon.start();
}
}
/**
* Stop the applet.
*/
public synchronized void stop() {
if (ssp != null) {
ssp.stop();
ssp = null;
}
if (daemon != null) {
daemon.stopticker();
daemon = null;
}
}
}
class TickerPaintDaemon extends Thread {
StockTicker ticker;
public TickerPaintDaemon(StockTicker ticker) {
this.ticker = ticker;
}
public synchronized void run() {
while (ticker != null && ticker.daemon == this) {
ticker.scroll();
try {
wait(ticker.deltat);
} catch (InterruptedException e) {
break;
}
}
}
public synchronized void stopticker() {
ticker = null;
notify();
}
}
class QuoteSnapshot {
StockTicker ticker;
String symbol;
float quote;
float prev;
Color color;
int width;
QuoteSnapshot next;
String QuoteWholeStr;
String QuoteFractStr;
String DiffWholeStr;
String DiffFractStr;
static int margin = 15;
public QuoteSnapshot(StockTicker t, String s, float q, float p, Color c) {
set(t, s, q, p, c);
}
public void set(StockTicker t, String s, float q, float p, Color c) {
ticker = t;
symbol = s;
quote = q;
prev = p;
color = c;
QuoteWholeStr = formatwhole(quote);
QuoteFractStr = formatfract(quote);
DiffWholeStr = formatdiff(quote, prev);
DiffFractStr = formatdifffract(quote, prev);
width = margin +
ticker.symbolFM.stringWidth(symbol) + 1 +
ticker.quoteFM.stringWidth(QuoteWholeStr) + 1 +
ticker.fractFM.stringWidth(QuoteFractStr) + 2 +
ticker.quoteFM.stringWidth(DiffWholeStr) + 1 +
ticker.fractFM.stringWidth(DiffFractStr);
}
private String formatwhole(float q) {
return Float.toString((float) Math.floor(q));
}
private String formatfract(float q) {
int numerator = (int) ((q - Math.floor(q)) * 16);
int denominator = 16;
while (numerator != 0 && (numerator & 1) == 0) {
numerator >>= 1;
denominator >>= 1;
}
return (numerator == 0) ? "" : (numerator + "/" + denominator);
}
private String formatdiff(float now, float before) {
float diff = now - before;
if (diff == 0)
return "";
int wholediff = (int) Math.floor(Math.abs(diff));
String s = (diff < 0) ? "-" : "+";
if (wholediff != 0)
s = s + wholediff;
return s;
}
private String formatdifffract(float now, float before) {
float diff = now - before;
return (diff == 0) ? "" : formatfract(Math.abs(diff));
}
public int paint(Graphics g, int pos) {
int baseline = ticker.symbolFM.getAscent();
g.setColor(ticker.bgColor);
g.fillRect(pos, 0, width, ticker.symbolFM.getHeight());
g.setColor(color);
g.setFont(ticker.symbolFont);
g.drawString(symbol, pos, baseline);
pos += ticker.symbolFM.stringWidth(symbol) + 1;
g.setFont(ticker.quoteFont);
g.drawString(QuoteWholeStr, pos, baseline);
pos += ticker.quoteFM.stringWidth(QuoteWholeStr) + 1;
g.setFont(ticker.fractFont);
g.drawString(QuoteFractStr, pos, baseline);
pos += ticker.fractFM.stringWidth(QuoteFractStr) + 2;
g.setFont(ticker.quoteFont);
g.drawString(DiffWholeStr, pos, baseline);
pos += ticker.quoteFM.stringWidth(DiffWholeStr) + 1;
g.setFont(ticker.fractFont);
g.drawString(DiffFractStr, pos, baseline);
pos += ticker.fractFM.stringWidth(DiffFractStr) + margin;
return pos;
}
}
class QuoteQueue {
QuoteSnapshot freeList;
QuoteSnapshot queueHead;
QuoteSnapshot queueTail;
public QuoteQueue() {
}
public QuoteSnapshot enqueue(StockTicker t, String s,
float q, float p, Color c) {
QuoteSnapshot qs;
if (freeList == null) {
qs = new QuoteSnapshot(t, s, q, p, c);
} else {
qs = freeList;
freeList = qs.next;
qs.set(t, s, q, p, c);
}
qs.next = null;
if (queueTail == null) {
queueHead = qs;
} else {
queueTail.next = qs;
}
queueTail = qs;
return qs;
}
public void dequeue() {
QuoteSnapshot qs = queueHead;
if (queueTail == qs) {
queueHead = queueTail = null;
} else {
queueHead = qs.next;
}
qs.next = freeList;
freeList = qs;
}
public QuoteSnapshot getHead() {
return queueHead;
}
}